#ifndef __SLOTHTTPD_STAGE_PROXY_FCGI_HPP__
#define __SLOTHTTPD_STAGE_PROXY_FCGI_HPP__

#include <slothttpd/ref_counted.hpp>
#include <slothttpd/server.hpp>
#include <slothttpd/fcgi/application.hpp>
#include <slothttpd/parser/headers_parser.hpp>
#include <slothttpd/config/location/fcgi_location.hpp>

#include <string>

#include <boost/intrusive_ptr.hpp>
#include <boost/asio.hpp>

namespace slothttpd {

namespace stage {

class proxy_fcgi;
typedef boost::intrusive_ptr<proxy_fcgi> proxy_fcgi_ptr;

class proxy_fcgi :
        public ref_counted
{
public:
    proxy_fcgi(connection_ptr conn, config::fcgi_location &conf);
    
private:
    enum stdin_state_type {
        stdin_params,
        stdin_content,
        stdin_done
    };
    
    enum stdout_state_type {
        stdout_parse_headers,
        stdout_content
    };
    
    static char_range_t next_buffer(proxy_fcgi_ptr f);
    static void handle_event(proxy_fcgi_ptr f, char *record, const boost::system::error_code &err);
    
    static void handle_write_response(proxy_fcgi_ptr f, const boost::system::error_code &err);
    
    void post_write_chunk();
    static void handle_write_chunk(proxy_fcgi_ptr f, const boost::system::error_code &err);
    
    void post_write_final_chunk();
    static void handle_write_final_chunck(proxy_fcgi_ptr f, const boost::system::error_code &err);
    
    static void store_len(char **const b, std::uint32_t len);
    bool append_params();
    
    void header_found(char_range_t name, char_range_t value);
    
private:
    fcgi::multiplexer::request_controller  request_;
    
    config::fcgi_location      &conf_;
    data_buffer                 out_buffer_;
    receive_buffer_list         stdout_buffers_;
    receive_buffer_list         stderr_buffers_;
    
    stdout_state_type           stdout_state_;
    parser::headers_parser      stdout_parser_;
    
    boost::array<char, 16>       chunk_size_;
    
    // if we got some data already from fcgi app we can't send HTTP stock responses
    bool                        stdout_sent_;
    bool                        write_pending_;
    std::size_t                 stdout_sending_;
    boost::array<boost::asio::const_buffer, 3> three_buffers;
    
    //volatile params_state_type  params_state_;
    config::fcgi_location::params_range_t params_state_;
    stdin_state_type            stdin_state_;
    std::size_t                 stdin_left_;
};

}
}

#endif
